use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use crate::builder::Builder;
use crate::database::TableField;
use crate::utils::underline_to_hump;

// xml构建
#[derive(Debug)]
pub struct XmlBuilder {
    base_path: String,
    table_name: String,
    // 属性列表
    fields: Vec<TableField>,
    // 命名空间
    namespace: String,
    // 映射实体
    result_type: String,
}

impl XmlBuilder {

    pub fn new(base_path: &str, table_name: &str, namespace: &str, result_type: &str, fields: Vec<TableField>) -> Self {
        XmlBuilder {
            base_path: base_path.to_string(),
            table_name: table_name.to_string(),
            namespace: namespace.to_string(),
            result_type: result_type.to_string(),
            fields,
        }
    }

    fn parent_start(&self) -> String {
        format!("<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-builder.dtd\">
\n<mapper namespace=\"{}\">\n", self.namespace)
    }

    fn parent_end(&self) -> String {
        format!("\n</mapper>")
    }

    fn base_column_list(&self) -> String {
        let x: Vec<&str> = self.fields.iter().map(|node| node.field_name.as_str()).collect();
        format!("\t<!-- 通用查询结果列 -->\n\t<sql id=\"Base_Column_List\">\n\t\t{}\n\t</sql>", x.join(",").to_string())
    }

    /**
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.cwz.common.builder.ApplyProductDetail">
        <id column="id" property="id" />
        <result column="product_apply_id" property="productApplyId" />
        <result column="picture_path" property="picturePath" />
        <result column="high" property="high" />
        <result column="width" property="width" />
        <result column="create_time" property="createTime" />
    </resultMap>
     */
    fn base_result_map(&self) -> String {
        let mut string = String::from("");
        let first = format!("\t<!-- 通用查询映射结果 -->\n\t<resultMap id=\"BaseResultMap\" type=\"{}\">\n", self.result_type);
        string.push_str(first.as_str());
        self.fields.iter().for_each(|item| {
            if item.field_key.eq("PRI") {
                string.push_str(format!("\t\t<id column=\"{}\" property=\"{}\" />\n", item.field_name, underline_to_hump(item.field_name.clone(), false)).as_str());
            } else {
                string.push_str(format!("\t\t<result column=\"{}\" property=\"{}\" />\n", item.field_name, underline_to_hump(item.field_name.clone(), false)).as_str());
            }
        });
        let end = format!("\t</resultMap>\n");
        string.push_str(end.as_str());
        string.to_string()
    }
}

impl Builder for XmlBuilder {

    fn build(&self) -> String {
        let mut result = String::from("");
        result.push_str(self.parent_start().as_str());
        result.push_str(self.base_result_map().as_str());
        result.push_str(self.base_column_list().as_str());
        result.push_str(self.parent_end().as_str());
        result.to_string()
    }

    fn build_file(&self) {
        let parent_path = format!("{}/{}", self.base_path, self.table_name);
        fs::create_dir_all(Path::new(parent_path.as_str())).unwrap();
        let file_name = format!("{}/{}Mapper.xml", parent_path, underline_to_hump(self.table_name.clone(), true));
        // println!("{}", file_name);
        let mut file = File::create(file_name).unwrap();
        file.write_all(self.build().as_bytes()).unwrap();
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_file() {
        //
        let parent_path = format!("{}/{}", "resource/test", "demo_one");
        fs::create_dir_all(&Path::new(parent_path.as_str())).unwrap();
        let file_name = format!("{}/{}Mapper.xml", parent_path, underline_to_hump("demo_one".to_string(), true));
        println!("{}", file_name);
        let mut file = File::create(&Path::new(file_name.as_str())).unwrap();
        file.write_all("aaaaaaaa".as_bytes()).expect("TODO: panic message");
    }

    #[test]
    fn test() {

    }
}